/**
 * system.c
 * Implementasi untuk modul system
 * Modul system berfungsi untuk mengendalikan semua proses yang berhubungan dengan sistem program
 * Seperti: pembacaan perintah, eksekusi perintah, pembacaan dari file, penanganan query
 * Fri, 4 Dec 2009
 * By Karol Danutama 13508040
 * */

#include "system.h"

/** Macro definition untuk memperpendek sintaks **/
#define load IsStringEqual(LowerCase(Argument(command , 1)) , LoadCommand)
#define open IsStringEqual(LowerCase(Argument(command , 1)) , OpenCommand)
#define save IsStringEqual(LowerCase(Argument(command , 1)) , SaveCommand)
#define addsite IsStringEqual(LowerCase(Argument(command , 1)) , AddSiteCommand)
#define addconn IsStringEqual(LowerCase(Argument(command , 1)) , AddConnCommand)
#define create IsStringEqual(LowerCase(Argument(command , 1)) , CreateCommand)
#define reset IsStringEqual(LowerCase(Argument(command , 1)) , ResetCommand)
#define list IsStringEqual(LowerCase(Argument(command , 1)) , ListCommand)
#define exit IsStringEqual(LowerCase(Argument(command , 1)) , ExitCommand)

#define sites IsStringEqual(LowerCase(Argument(command , 2)) , ArgSites)
#define servers IsStringEqual(LowerCase(Argument(command , 2)) , ArgServers)
#define connections IsStringEqual(LowerCase(Argument(command , 2)) , ArgConnections)
#define clients IsStringEqual(LowerCase(Argument(command , 2)) , ArgClients)
#define tables IsStringEqual(LowerCase(Argument(command , 2)) , ArgTables)
#define ASC IsStringEqual(LowerCase(Argument(command , 2)) , ArgASC)
#define DESC IsStringEqual(LowerCase(Argument(command , 2)) , ArgDESC)

#define retrieve IsStringEqual(LowerCase(Argument(command , 1)) , RetrieveCommand)
#define insert IsStringEqual(LowerCase(Argument(command , 1)) , InsertCommand) && IsStringEqual(LowerCase(Argument(command , 2)) , CharToString("into"))
#define delete IsStringEqual(LowerCase(Argument(command , 1)) , DeleteCommand) && IsStringEqual(LowerCase(Argument(command , 2)) , CharToString("from"))
#define update IsStringEqual(LowerCase(Argument(command , 1)) , UpdateCommand) && IsStringEqual(LowerCase(Argument(command , 2)) , CharToString("table"))
#define close IsStringEqual(LowerCase(Argument(command , 1)) , CloseCommand)

#define cts(s) CharToString(s)

void AssignConstantValue() {
	/**
	 * Memberikan nilai ke PSEUDOCONSTANT dengan memanfaatkan fungsi konversi CharToString
	 * */
	
	ExitCommand = CharToString("exit");
	LoadCommand = CharToString("load");
	OpenCommand = CharToString("open");
	SaveCommand = CharToString("save");
	AddSiteCommand = CharToString("addsite");
	AddConnCommand = CharToString("addconn");
	CreateCommand = CharToString("create");
	ResetCommand = CharToString("reset");
	ListCommand = CharToString("list");
	
	ArgSites = CharToString("sites");
	ArgConnections = CharToString("connections");
	ArgServers = CharToString("servers");
	ArgClients = CharToString("clients");
	ArgTables = CharToString("tables");
	ArgASC = CharToString("asc");
	ArgDESC = CharToString("desc");
	ArgAll = CharToString("*");
	
	RetrieveCommand = CharToString("retrieve");
	InsertCommand = CharToString("insert");
	DeleteCommand = CharToString("delete");
	UpdateCommand = CharToString("update");
	CloseCommand = CharToString("close");
	
	StudentsTable = cts("mahasiswa");
	LecturesTable = cts("matakuliah");
	Lectures_StudentsTable = cts("pengambilanmk");
	
	NULLValue = cts("NULL");
}

void SetError(int ErrCode) {
	string e[100]; //variabel penampung error message
	
	//Memberikan nilai error message sesuai dengan error code
	e[0] = CharToString("Unknown error");
	e[1] = CharToString("Invalid file description");
	e[2] = CharToString("Node not found");
	e[3] = CharToString("Invalid argument. Try [command] -help");
	e[4] = CharToString("Command error");
	e[5] = CharToString("File not found");
	e[6] = CharToString("Unknown cell type");
	e[7] = CharToString("Table not found");
	e[8] = CharToString("Illegal site");
	e[9] = CharToString("Wrong column number");
	e[10] = CharToString("Syntax error");
	e[11] = CharToString("Destination unreachable, no connection path found");
	e[12] = CharToString("Table not exists");
	e[13] = CharToString("Maximum node count reached");
	e[14] = CharToString("Table already exists");
	e[15] = CharToString("Site name already exists");
	
	
	printf("Error %d : %s\n" , ErrCode , e[ErrCode].s);
}

void CreateEmptyCommand(Command *c) {
	c->nArgument = 0;
}

Command ReadCommand(FILE *f , int modus , TNodeList *NodeList , int currentNode) {
	//Membaca perintah dari masukkan pengguna
	
	Command c;
	int i = 0;
	
	CreateEmptyCommand(&c);
	
	string nodeName = GetActualNodeName(NodeList , currentNode);
	
	if (modus == 1) printf("> "); else if (modus == 2) printf("%s >> " , nodeName.s);
	
	//Membaca pita karakter dan menyimpan secara terpisah dalam beberapa string
	StartString(f);
	while (!end) {
		i++;
		c.nArgument = i;
		c.argument[i] = cString;
		AdvString(f);
	}
	
	//printf("%d\n" , nArgument(tA));
	return c;
}


Command MergeArguments(Command c) {
	//KAMUS LOKAL
	int i , n = 0;
	Command ctemp;
	
	//INISIALISASI
	CreateEmptyCommand(&ctemp);
	
	//ALGORITMA
	forup(i,1,nArgument(c)) {
		if (Argument(c,i).s[0] == '"') {
			n++;
			ctemp.nArgument = n;
			ctemp.argument[n] = MergeString(&i , c);
			i--;
		}
		else {
			n++;
			ctemp.nArgument = n;
			ctemp.argument[n] = c.argument[i];
		}
	}
	
	return ctemp;
}


Command ReadArguments(FILE *f) {
	//KAMUS LOKAL
	Command c;
	int i = 0 , n = 0;
	
	
	//ALGORITMA
	CreateEmptyCommand(&c);
	
	//Membaca pita karakter dan menyimpan secara terpisah dalam beberapa string
	StartString(f);
	while (!end && !IsStringEqual(LowerCase(cString) , CharToString("@end"))) {
		i++;
		c.nArgument = i;
		c.argument[i] = cString;
		AdvString(f);
	}
	
	if (IsStringEqual(LowerCase(cString) , CharToString("@end"))) {
		nArgument(c) = 1;
		Argument(c , 1) = CharToString("@end");
	}
	else
		c = MergeArguments(c); //Membersihkan c dari nilai string
		
	return c;
}

string MergeString(int *iterator , Command a) {
	//KAMUS LOKAL
	string retval = CharToString("");
	
	//LOOPING HINGGA " DITEMUKAN ATAU AKHIR DARI PERINTAH
	do {
		retval = StrCat(retval , StrCat(CharToString(" ") , Argument(a , *iterator)));
		*iterator = *iterator + 1;
		//printf("%d\n" , *iterator);
	} while (*iterator <= nArgument(a) && Argument(a , *iterator - 1).s[Argument(a , *iterator - 1).length - 1] != '"');
	
	//BERSIHKAN DARI KARAKTER "
	retval = DeleteSubString(retval , 0 , 2);
	retval = DeleteSubString(retval , retval.length-1 , 1);
	return retval;
}

void ExecuteCommand(int *modus , TNodeList *NodeList , TAdjMatrix m , TAdjList *a , int *currentNode , string *currentFile) {
	//KAMUS LOKAL
	int i , j , node , err , org , dest;
	TNodeList nl;
	TTabstudents ts;
	TTablectures tl;
	TTablectures_students rel;
	string cond[3] , col[10];
	FILE *f;
	
	//ALGORITMA What a loooong conditional -_-
	if (*modus == 1) {
		if (load) { //load
			if (nArgument(command) == 2) {
				//INISIALISASI, Kosongkan struktur data internal
				CreateEmptyAdjMatrix(m);
				CreateEmptyNodeList(NodeList);
				CreateEmptyAdjList(a);
				
				//BACA DARI FILE
				f = fopen(Argument(command , 2).s , "r");
				if (f != NULL) { //file ada secara fisik
					ReadExternalStructure(f , NodeList , m , a);
					printf("File %s loaded successfully\n" , Argument(command , 2).s);
					*currentFile = Argument(command , 2);
					fclose(f);
				}
				else //file tidak ada secara fisik
					SetError(5);
			}
			else
				SetError(3);
		} else
		if (open) { //open
			if (nArgument(command) == 2) {
				
				//Mencari alamat fisik dari sebuah node
				*currentNode = GetPhysicalNodeName(NodeList , Argument(command , 2));
				
				if (*currentNode == null) { //jika alamat fisik tidak ditemukan
					SetError(2);
					*currentNode = 0;
				}
				else if (NodeList->node[*currentNode].isClient) { //jika node yang dituju adalah client
					*modus = 2;
					printf("You are now at node %s\n" , Argument(command , 2).s);
				}
				else //bukan client
					SetError(8);
			}
			else
				SetError(3);
		} else
		if (save) { //save
			if (nArgument(command) == 1) { //menyimpan ke file saat ini
				f = fopen(currentFile->s , "w");
				WriteToExternalStructure(f, NodeList , m , *a);
				printf("State saved successfully to %s\n" , currentFile->s);
				fclose(f);
			}
			else if (nArgument(command) == 2) { //menyimpan ke file lain
				f = fopen(Argument(command , 2).s , "w");
				WriteToExternalStructure(f, NodeList , m , *a);
				printf("State saved successfully to %s\n" , Argument(command , 2).s);
				fclose(f);
			}
			else
				SetError(3);
		} else
		if (reset) { //reset
			if (nArgument(command) == 1) {
				f = fopen(currentFile->s , "r");
				if (f != NULL) { //sama seperti perintah open
					CreateEmptyNodeList(NodeList);
					CreateEmptyAdjMatrix(m);
					CreateEmptyAdjList(a);
					ReadExternalStructure(f , NodeList , m , a);
					printf("State resetted successfully as %s\n" , currentFile->s);
					fclose(f);
				}
				else
					SetError(5);
			}
			else
				SetError(3);
		} else
		if (addsite) { //addsite
			if (nArgument(command) == 5) {
				//Memeriksa apakah AddNode mengembalikan errcode 0 atau tidak
				err = AddNode(NodeList , CreateNode(Argument(command , 2) , IsStringEqual(UpperCase(Argument(command , 3)) , CharToString("Y")) , IsStringEqual(UpperCase(Argument(command , 4)) , CharToString("Y")) , StringToFloat(Argument(command , 5))));
				if (!err)
					printf("Node %s added successfully\n" , Argument(command , 2).s);
				else
					SetError(err);
			}
			else
				SetError(3);
		} else
		if (addconn) { //addconn
			if (nArgument(command) == 4) {
				//Alamat fisik dari node
				org = GetPhysicalNodeName(NodeList , Argument(command , 2));
				dest = GetPhysicalNodeName(NodeList , Argument(command , 3));
				err = AddEdge(m , a , org , dest , StringToFloat(Argument(command , 4)));
				if (!err)
					printf("Connection from %s to %s created successfully\n" , Argument(command , 2).s , Argument(command , 3).s);
				else
					SetError(err);
			}
			else
				SetError(3);
		} else
		if (create) { //create
			if (nArgument(command) == 3) {
				//alamat fisik dari sebuah node
				node = GetPhysicalNodeName(NodeList , Argument(command , 3));
				if (node != null) { //jika alamat fisik ditemukan
					if (IsStringEqual(LowerCase(Argument(command , 2)) , StudentsTable)) { //buat tabel mahasiswa
						err = CreateStudentsTable(&(NodeList->node[node]));
						if (!err)
							printf("Students table successfully created at site %s\n" , Argument(command , 3).s);
						else
							SetError(err);
					}
					else if (IsStringEqual(LowerCase(Argument(command , 2)) , LecturesTable)) { //buat tabel matakuliah
						err = CreateLecturesTable(&(NodeList->node[node]));
						if (!err)
							printf("Lectures table successfully created at site %s\n" , Argument(command , 3).s);
						else
							SetError(err);
					}
					else if (IsStringEqual(LowerCase(Argument(command , 2)) , Lectures_StudentsTable)) { //buat tabel pengambilanmk
						err = CreateLectures_StudentsTable(&(NodeList->node[node]));
						if (!err)
							printf("Lectures_students table successfully created at site %s\n" , Argument(command , 3).s);
						else
							SetError(err);
					}
					else
						SetError(3);
				}
				else
					SetError(2);
			}
			else
				SetError(3);
		} else
		if (list) { //list
			if (nArgument(command) == 1) {
				printf("Sites : \n");
				PrintNodeList(NodeList , true);
				printf("Connections : \n");
				PrintAdjList(*a , NodeList , true);
			}
			else if (nArgument(command) == 2) {
				if (sites) {
					printf("Sites : \n");
					PrintNodeList(NodeList , true);
				}
				else if (connections) {
					printf("Connections : \n");
					PrintAdjList(*a , NodeList , true);
				}
				else if (servers) {
					nl = FilterServers(NodeList);
					PrintNodeList(&nl , true);
				}
				else if (clients) {
					nl = FilterClients(NodeList);
					PrintNodeList(&nl , true);
				}
				else if (tables) {
					ts = MergeTabStudent(NodeList);
					tl = MergeTabLecture(NodeList);
					rel = MergeTabRelation(NodeList);
					printf("Mahasiswa     :   %d\n" , ts.NStudents);
					printf("MataKuliah    :   %d\n" , tl.NLectures);
					printf("PengambilanMK :   %d\n" , rel.NRelation);
				}
				else if (IsStringEqual(UpperCase(Argument(command , 2)) , CharToString("ASC")) || IsStringEqual(UpperCase(Argument(command , 2)) , CharToString("DESC"))) {
					printf("Sites : \n");
					PrintNodeList(NodeList , IsStringEqual(UpperCase(Argument(command , 2)) , CharToString("ASC")));
					printf("Connections : \n");
					PrintAdjList(*a , NodeList , IsStringEqual(UpperCase(Argument(command , 2)) , CharToString("ASC")));
				}
				else
					SetError(3);
			}
			else if (nArgument(command) == 3 && (IsStringEqual(UpperCase(Argument(command , 3)) , CharToString("ASC")) || IsStringEqual(UpperCase(Argument(command , 3)) , CharToString("DESC")))) {
				if (sites) {
					printf("Sites : \n");
					PrintNodeList(NodeList , IsStringEqual(UpperCase(Argument(command , 3)) , CharToString("ASC")));
				}
				else if (connections) {
					printf("Connections : \n");
					PrintAdjList(*a , NodeList , IsStringEqual(UpperCase(Argument(command , 3)) , CharToString("ASC")));
				}
				else if (servers) {
					nl = FilterServers(NodeList);
					PrintNodeList(&nl , IsStringEqual(UpperCase(Argument(command , 3)) , CharToString("ASC")));
				}
				else if (clients) {
					nl = FilterClients(NodeList);
					PrintNodeList(&nl , IsStringEqual(UpperCase(Argument(command , 3)) , CharToString("ASC")));
				}
				else if (tables) {
					ts = MergeTabStudent(NodeList);
					tl = MergeTabLecture(NodeList);
					rel = MergeTabRelation(NodeList);
					if (IsStringEqual(UpperCase(Argument(command , 3)) , CharToString("ASC"))) {
						printf("Mahasiswa     :   %d\n" , ts.NStudents);
						printf("MataKuliah    :   %d\n" , tl.NLectures);
						printf("PengambilanMK :   %d\n" , rel.NRelation);
					}
					else {
						printf("PengambilanMK :   %d\n" , rel.NRelation);
						printf("MataKuliah    :   %d\n" , tl.NLectures);
						printf("Mahasiswa     :   %d\n" , ts.NStudents);
					}
				}
				else
					SetError(3);
			}
			else
				SetError(3);
		}
		else
			SetError(4);
	}
	else if (*modus == 2) {
		if (retrieve) {
			Retrieve(command , (TAdjMatrix*)(m) , NodeList , *currentNode);
		} 
		else if (insert) {
			Insert(command , (TAdjMatrix*)(m) , NodeList , *currentNode);
		} 
		else if (delete) {
			Delete(command , (TAdjMatrix*)(m) , NodeList , *currentNode);
		} 
		else if (update) {
			Update(command , (TAdjMatrix*)(m) , NodeList , *currentNode);
		} 
		else if (close) {
			*modus = 1;
		} 
		else
			SetError(4);
	}
}


void ReadExternalStructure(FILE *f , TNodeList *nodes , TAdjMatrix m , TAdjList *AdjList) {
	//KAMUS LOKAL
	Command a;
	TNode node;
	int currentNode = 0 , i;
	int currentTable = 0 , org , dest;
	
	//ALGORITMA
	a = ReadArguments(f);
	
	if (nArgument(a) == 2 && IsStringEqual(LowerCase(Argument(a,1)) , CharToString("@nodes")))
		nodes->NNode = StringToInt(Argument(a,2));
	
	//MEMBACA NODES INFO
	a = ReadArguments(f);
	while(nArgument(a) != 2 && !IsStringEqual(LowerCase(Argument(a,1)) , CharToString("@edges"))) {
		if (IsStringEqual(SubString(Argument(a,1) , 0 , 2) , CharToString("@@"))) {
			currentNode++;
			nodes->node[currentNode].Name = SubString(Argument(a,1) , 2 , Argument(a,1).length - 2);
			nodes->node[currentNode].isServer = IsStringEqual(LowerCase(Argument(a,2)) , CharToString("y"));
			nodes->node[currentNode].isClient = IsStringEqual(LowerCase(Argument(a,3)) , CharToString("y"));
			nodes->node[currentNode].CPUTime = StringToFloat(Argument(a,4));
			node = nodes->node[currentNode];
		}
		else if (IsStringEqual(LowerCase(Argument(a,1)) , StudentsTable) && nArgument(a) == 1) {
			currentTable = 1;
			nodes->node[currentNode].IsStudentsExists = true;
		}
		else if (IsStringEqual(LowerCase(Argument(a,1)) , LecturesTable) && nArgument(a) == 1) {
			currentTable = 2;
			nodes->node[currentNode].IsLecturesExists = true;
		}
		else if (IsStringEqual(LowerCase(Argument(a,1)) , Lectures_StudentsTable) && nArgument(a) == 1) {
			currentTable = 3;
			nodes->node[currentNode].IsLectures_StudentsExists = true;
		}
		else {
			
			if (currentTable == 1 && nArgument(a) == 6 && nodes->node[currentNode].isServer) {
				InsertStudentsRow(&(nodes->node[currentNode].students) , CreateStudent(Argument(a,1) , Argument(a,2) , ParseDate(Argument(a,3)) , Argument(a,4) , StringToFloat(Argument(a,5)) , StringToInt(Argument(a,6))));
			}
			else if (currentTable == 2 && nArgument(a) == 4 && nodes->node[currentNode].isServer) {
				InsertLecturesRow(&(nodes->node[currentNode].lectures) , CreateLecture(Argument(a,1) , Argument(a,2) , StringToInt(Argument(a,3)) , Argument(a,4)));
			}
			else if (currentTable == 3 && nArgument(a) == 5  && nodes->node[currentNode].isServer) {
				InsertLectures_StudentsRow(&(nodes->node[currentNode].lectures_students) , CreateRelation(Argument(a,1) , Argument(a,2) , StringToInt(Argument(a,3)) , StringToThnAkademik(Argument(a,4)) , Argument(a,5).s[0]));
			}
		}
		a = ReadArguments(f);
	}
	
	//NodeList di-sort dulu kk
	*nodes = SortNodeListByName(nodes);
	
	//MEMBACA CONNECTIONS
	a = ReadArguments(f);
	while(!IsStringEqual(LowerCase(Argument(a,1)) , CharToString("@end"))) {
		org = GetPhysicalNodeName(nodes , Argument(a,1));
		
		dest = GetPhysicalNodeName(nodes , Argument(a,2));
		
		//MASUKKAN KE ADJ MATRIX
		if (StringToFloat(Argument(a,3)) > m[org][dest]) {
			m[org][dest] = StringToFloat(Argument(a,3));
			m[dest][org] = StringToFloat(Argument(a,3));
		}
		
		//MASUKKAN KE ADJ LIST
		AdjList->NEdge++;
		AdjList->edge[AdjList->NEdge].org = org;
		AdjList->edge[AdjList->NEdge].dest = dest;
		AdjList->edge[AdjList->NEdge].bandwidth = StringToFloat(Argument(a,3));
		a = ReadArguments(f);
	}
	
	//AdjList juga di-sort dulu kk, biar enak
	*AdjList = SortAdjList(*AdjList);
}


void WriteToExternalStructure(FILE *f , TNodeList *nodes , TAdjMatrix m , TAdjList AdjList) {
	//KAMUS LOKAL
	int i , j , nedge = 0;
	TNode node;
	string t,d;
	string org , dest;
	
	
	//ALGORITMA
	fprintf(f , "@nodes\n%d #\n" , nodes->NNode);
	
	forup(i , 1 , nodes->NNode) {
		node = nodes->node[i];
		fprintf(f , "@@%s\n" , node.Name.s);
		if (node.isServer) fprintf(f , "Y "); else fprintf(f , "T ");
		if (node.isClient) fprintf(f , "Y "); else fprintf(f , "T ");
		fprintf(f , "%f #\n" , node.CPUTime);
		if (node.IsStudentsExists) {
			fprintf(f , "Mahasiswa #\n");
			forup(j , 1 , node.students.NStudents) {
				d = DateToString(node.students.t[j].TglLahir);
				fprintf(f , "%s \"%s\" %s %s " , node.students.t[j].NIM.s , node.students.t[j].Nama.s , d.s , node.students.t[j].KotaAsal.s);
				if (node.students.t[j].IPK == -1) fprintf(f , "NULL "); else fprintf(f , "%f " , node.students.t[j].IPK);
				if (node.students.t[j].JumlahSKS == -1) fprintf(f , "NULL #\n"); else fprintf(f , "%d #\n" , node.students.t[j].JumlahSKS);
			}
		}
		if (node.IsLecturesExists) {
			fprintf(f , "MataKuliah #\n");
			forup(j , 1 , node.lectures.NLectures) {
				fprintf(f , "%s \"%s\" %d %s #\n" , node.lectures.t[j].Kode.s , node.lectures.t[j].Nama.s , node.lectures.t[j].SKS , node.lectures.t[j].Bidang.s);
			}
		}
		if (node.IsLectures_StudentsExists) {
			fprintf(f , "PengambilanMK #\n");
			forup(j , 1 , node.lectures_students.NRelation) {
				t = ThnAkademikToString(node.lectures_students.t[j].ThnAkademik);
				fprintf(f , "%s \"%s\" %d %s %c #\n" , node.lectures_students.t[j].NIM.s , node.lectures_students.t[j].Kode.s , node.lectures_students.t[j].Semester , t.s , node.lectures_students.t[j].Nilai);
			}
		}
	}
	
	fprintf(f , "@edges\n%d #\n" , AdjList.NEdge);
	
	forup(i , 1 , AdjList.NEdge) {
		org = GetActualNodeName(nodes , AdjList.edge[i].org);
		dest = GetActualNodeName(nodes , AdjList.edge[i].dest);
		fprintf(f , "%s %s %f #\n" , org.s , dest.s , AdjList.edge[i].bandwidth);
	}
	
	fprintf(f , "@end\n");
}


void ParseCondition(Command c , int start , string cond[MaxConditionArgs] , int *ncond) {
	//KAMUS LOKAL
	int i;
	
	//ALGORITMA
	*ncond = 0;
	forup(i , start , nArgument(c)) {
		cond[*ncond] = Argument(c , i);
		(*ncond)++;
	}
}


//QUERY HANDLER
void Retrieve(Command C , TAdjMatrix *m , TNodeList *NodeList , int currentNode) {
	//KAMUS LOKAL
	Command c = MergeArguments(C);
	string col[10] , cond[MaxConditionArgs];
	string FROM = CharToString("FROM") , WHERE = CharToString("WHERE");
	string tableName;
	int ncol = 0 , i , ncond = 0;
	boolean isDetail;
	
	//ALGORITMA
	if (IsStringEqual(LowerCase(Argument(c , 2)) , CharToString("details"))) { //apakah diminta detail penarikan informasi
		i = 3;
		isDetail = true;
	}
	else {
		i = 2;
		isDetail = false;
	}
	
	//AMBIL NAMA KOLOM YANG INGIN DICARI
	while (!IsStringEqual(UpperCase(Argument(c , i)) , FROM) && i <= nArgument(c)) {
		ncol++;
		col[ncol] = Argument(c , i);
		i++;
	}
	
	if (i > nArgument(c)) //TIDAK ADA ARGUMEN FROM
		SetError(10);
	else {
		i++;
		tableName = Argument(c , i);
		i++;
		
		if (i > nArgument(c)) { //TIDAK ADA ARGUMEN WHERE
			i++;
			cond[0] = CharToString("-");
			ncond = 1;
		}
		else { //ADA ARGUMEN WHERE
			i++;
			ParseCondition(c , i , cond , &ncond);
		}
			
		if (IsStringEqual(LowerCase(tableName) , StudentsTable)) //mahasiswa
			RetrieveStudentsRecord((m) , NodeList , col , ncol , cond , ncond , isDetail , NodeList->node[currentNode]);
		else if (IsStringEqual(LowerCase(tableName) , LecturesTable)) //matakuliah
			RetrieveLecturesRecord((m) , NodeList , col , ncol , cond , ncond , isDetail , NodeList->node[currentNode]);
		else if (IsStringEqual(LowerCase(tableName) , Lectures_StudentsTable)) //pengambilanmk
			RetrieveLectures_StudentsRecord((m) , NodeList , col , ncol , cond , ncond , isDetail , NodeList->node[currentNode]);
		else
			SetError(7);
	}
}



void Insert(Command C , TAdjMatrix *m , TNodeList *NodeList , int currentNode) {
	//KAMUS LOKAL
	Command c = MergeArguments(C);
	int i , ncol = 0 , node;
	string tableName , DATA = CharToString("DATA") , SITE = CharToString("SITE") , col[10];
	TStudent s;
	TLecture l;
	TLectures_Students rel;
	boolean isStudents , isLectures , isLectures_Students;
	
	//ALGORITMA
	i = 3;
	tableName = LowerCase(Argument(c , i));
	
	//NAMA TABEL YANG INGIN DIOPERASIKAN
	isStudents = IsStringEqual(tableName , StudentsTable);
	isLectures = IsStringEqual(tableName , LecturesTable);
	isLectures_Students = IsStringEqual(tableName , Lectures_StudentsTable);
	
	if (!(IsStringEqual(tableName , StudentsTable) || IsStringEqual(tableName , LecturesTable) || IsStringEqual(tableName , Lectures_StudentsTable))) //NAMA TABEL SALAH
		SetError(7);
	else {
		i++;
		if (IsStringEqual(DATA , UpperCase(Argument(c , i)))) { //ADA ARGUMEN DATA
			i++;
			while (!IsStringEqual(SITE , UpperCase(Argument(c , i))) && i < nArgument(c)) { //AMBIL NAMA KOLOM YANG INGIN DITAMPILKAN
				ncol++;	
				col[ncol] = Argument(c , i);
				i++;
			}
			
			if (!IsStringEqual(UpperCase(Argument(c , i)) , SITE)) //TIDAK ADA ARGUMEN SITE
				SetError(10);
			else if ((isStudents && ncol != 6) || (isLectures && ncol != 4) || (isLectures_Students && ncol != 5)) //JUMLAH KOLOM TIDAK SESUAI
				SetError(9);
			else if (i + 1 == nArgument(c) && GetPhysicalNodeName(NodeList , Argument(c , i + 1)) != -1 && NodeList->node[GetPhysicalNodeName(NodeList , Argument(c , i + 1))].isServer) {
				node = GetPhysicalNodeName(NodeList , Argument(c , i + 1));
				if (isStudents && NodeList->node[node].IsStudentsExists) { //tabel mahasiswa dan ada tabelnya
					s = CreateStudent(col[1] , col[2] , ParseDate(col[3]) , col[4] , StringToFloat(col[5]) , StringToInt(col[6]));
					//PrintStudentInfo(s);
					InsertStudentsRecord((TAdjMatrix*)(m) ,  &(NodeList->node[node]) , NodeList , s , NodeList->node[currentNode]);
				}
				else if (isLectures && NodeList->node[node].IsLecturesExists) { //tabel matakuliah dan sudah pernah dibuat tabelnya
					l = CreateLecture(col[1] , col[2] , StringToInt(col[3]) , col[4]);
					//PrintLectureInfo(l);
					InsertLecturesRecord((TAdjMatrix*)m ,  &(NodeList->node[node]) , NodeList , l , NodeList->node[currentNode]);
				}
				else if (isLectures_Students && NodeList->node[node].IsLectures_StudentsExists) { //tabel pengambilanmk dan sudah pernah dibuat tabelnya
					rel = CreateRelation(col[1] , col[2] , StringToInt(col[3]) , StringToThnAkademik(col[4]) , col[5].s[0]);
					//PrintRelationInfo(rel);
					InsertLectures_StudentsRecord((TAdjMatrix*)m ,  &(NodeList->node[node]) , NodeList , rel , NodeList->node[currentNode]);
				}
				else
					SetError(12);
			}
			else
				SetError(10);
		}
		else
			SetError(10);
	}
	
}

void Update(Command C , TAdjMatrix *m , TNodeList *NodeList , int currentNode) {
	//KAMUS LOKAL
	Command c = MergeArguments(C);
	int i , ncol = 0 , sks , ncond = 0;
	string tableName , DATA = CharToString("DATA") , WHERE = CharToString("WHERE") , col[10] , cond[MaxConditionArgs];
	Date TglLahir;
	TAcademicYear ThnAkademik;
	float ipk;
	TStudent s;
	TLecture l;
	TLectures_Students rel;
	boolean isStudents , isLectures , isLectures_Students;
	
	//ALGORITMA
	i = 3;
	tableName = LowerCase(Argument(c , i));
	
	//NAMA TABEL YANG INGIN DIOPERASIKAN
	isStudents = IsStringEqual(tableName , StudentsTable);
	isLectures = IsStringEqual(tableName , LecturesTable);
	isLectures_Students = IsStringEqual(tableName , Lectures_StudentsTable);
	
	if (!(IsStringEqual(tableName , StudentsTable) || IsStringEqual(tableName , LecturesTable) || IsStringEqual(tableName , Lectures_StudentsTable))) //NAMA TABEL SALAH
		SetError(7);
	else {
		i++;
		if (IsStringEqual(DATA , UpperCase(Argument(c , i)))) {
			i++;
			while (!IsStringEqual(WHERE , UpperCase(Argument(c , i))) && i <= nArgument(c)) {
				ncol++;	
				col[ncol] = Argument(c , i);
				i++;
			}
			
			if ((isStudents && ncol != 6) || (isLectures && ncol != 4) || (isLectures_Students && ncol != 5))
				SetError(9);
			else {
				i++;
				
				if (i > nArgument(c)) { //TIDAK ADA ARGUMEN WHERE
					cond[0] = CharToString("-");
					ncond = 1;
				}
				else
					ParseCondition(c , i , cond , &ncond);
					
				if (isStudents) {
					TglLahir = (IsStringEqual(col[3] , CharToString("-"))) ? ParseDate(CharToString("00-00-000")) : ParseDate(col[3]);
					ipk = (IsStringEqual(col[5] , CharToString("-"))) ? null : StringToFloat(col[5]);
					sks = (IsStringEqual(col[6] , CharToString("-"))) ? null : StringToInt(col[6]);
					s = CreateStudent(col[1] , col[2] , TglLahir , col[4] , ipk , sks);
					UpdateStudentsTable((TAdjMatrix*)m , NodeList , s , cond , ncond , NodeList->node[currentNode]);
				}
				else if (isLectures) {
					sks = (IsStringEqual(col[3] , CharToString("-"))) ? null : StringToInt(col[3]);
					l = CreateLecture(col[1] , col[2] , sks , col[4]);
					UpdateLecturesTable((TAdjMatrix*)m , NodeList , l , cond , ncond , NodeList->node[currentNode]);
				}
				else if (isLectures_Students) {
					sks = (IsStringEqual(col[3] , CharToString("-"))) ? null : StringToInt(col[3]);
					ThnAkademik = (IsStringEqual(col[4] , CharToString("-"))) ? StringToThnAkademik(CharToString("0000-0000")) : StringToThnAkademik(col[4]);
					rel = CreateRelation(col[1] , col[2] , sks , ThnAkademik , col[5].s[0]);
					UpdateLectures_StudentsTable((TAdjMatrix*)m , NodeList , rel , cond , ncond , NodeList->node[currentNode]);
				}
			}
		}
		else
			SetError(10);
	}
}


void Delete(Command C , TAdjMatrix *m , TNodeList *NodeList , int currentNode) {
	//KAMUS LOKAL
	Command c = MergeArguments(C);
	string cond[MaxConditionArgs];
	int i , ncond = 0;
	string tableName , WHERE = CharToString("WHERE");
	boolean isStudents , isLectures , isLectures_Students;
	
	//ALGORITMA
	i = 3;
	tableName = LowerCase(Argument(c , i));
	
	//NAMA TABEL
	isStudents = IsStringEqual(tableName , StudentsTable);
	isLectures = IsStringEqual(tableName , LecturesTable);
	isLectures_Students = IsStringEqual(tableName , Lectures_StudentsTable);
	
	if (!(IsStringEqual(tableName , StudentsTable) || IsStringEqual(tableName , LecturesTable) || IsStringEqual(tableName , Lectures_StudentsTable))) //NAMA TABEL SALAH
		SetError(7);
	else {
		i++;
		if (IsStringEqual(UpperCase(Argument(c , i)) , WHERE)) { //ADA ARGUMEN WHERE
			
			i++;

			ParseCondition(c , i , cond , &ncond);
				
			if (isStudents) {
				DeleteStudentsRecord((TAdjMatrix*)m , NodeList , cond , ncond , NodeList->node[currentNode]);
			}
			else if (isLectures) {
				DeleteLecturesRecord((TAdjMatrix*)m , NodeList , cond , ncond , NodeList->node[currentNode]);
			}
			else if (isLectures_Students) {
				DeleteLectures_StudentsRecord((TAdjMatrix*)m , NodeList , cond , ncond , NodeList->node[currentNode]);
			}
		}
		else if (i > nArgument(c)) { //TIDAK ADA ARGUMEN WHERE

			cond[0] = CharToString("-");
			ncond = 1;
				
			if (isStudents) {
				DeleteStudentsRecord((TAdjMatrix*)m , NodeList , cond , ncond , NodeList->node[currentNode]);
			}
			else if (isLectures) {
				DeleteLecturesRecord((TAdjMatrix*)m , NodeList , cond , ncond , NodeList->node[currentNode]);
			}
			else if (isLectures_Students) {
				DeleteLectures_StudentsRecord((TAdjMatrix*)m , NodeList , cond , ncond , NodeList->node[currentNode]);
			}
		}
	}
	
}
